import * as XLSX from 'xlsx'
import { getFormValues, getForeignValues, getTableList, doApi } from '@/api/basic'
import jsyaml from 'js-yaml'
import { useRoute } from 'vue-router'
import { merge, template, get } from 'lodash-es'
import { usePermissionStoreWithOut } from '@/store/modules/permission'
import { useValidator } from '@/hooks/web/useValidator'
import { useI18n } from '@/hooks/web/useI18n'
import PinyinEngine from 'pinyin-engine'
import Schema from 'async-validator'
import { ElMessage } from 'element-plus'
import { getTemplateData } from '@/modules/AutoGrid/tool'
import dayjs from 'dayjs'
import { StreamPreview, ContentEditor, FilePreview } from '@/modules/components/FilePreview'
import { createImageViewer } from '@/components/ImageViewer'

// 可配置的列属性
const configColumnAttrs = [
  'field',
  'title',
  'width',
  'min-width',
  'resizable',
  'visible',
  'fixed',
  'align',
  'header-align',
  'footer-align',
  'show-overflow',
  'show-header-overflow',
  'show-footer-overflow',
  'class-name',
  'header-class-name',
  'footer-class-name',
  'sortable',
  'sort-type',
  'filters',
  'filter-multiple'
]

// 可配置的表格属性
const configTableAttrs = [
  'height',
  'max-height',
  'auto-resize',
  'sync-resize',
  'stripe',
  'border',
  'round',
  'size',
  'loading',
  'align',
  'header-align',
  'footer-align',
  'show-header',
  'row-class-name',
  'cell-class-name',
  'header-row-class-name',
  'header-cell-class-name',
  'footer-row-class-name',
  'footer-cell-class-name',
  'show-footer',
  'show-overflow',
  'show-header-overflow',
  'show-footer-overflow',
  'keep-source',
  'column-config',
  'row-config',
  'resize-config',
  'resizable-config',
  'seq-config',
  'sort-config',
  'filter-config',
  'export-config',
  'import-config',
  'print-config',
  'radio-config',
  'checkbox-config',
  'tooltip-config',
  'expand-config',
  'tree-config',
  'menu-config',
  'mouse-config',
  'keyboard-config',
  'edit-config',
  'valid-config',
  'edit-rules',
  'empty-text',
  'empty-render',
  'loading-config',
  'custom-config',
  'scroll-x',
  'scroll-y',
  'params',
  'operation-width'
]
// 表格默认配置
const defaultTableConfig = {
  'header-align': 'left',
  align: 'left',
  'show-overflow': 'tooltip',
  'max-height': '100%',
  height: 'auto',
  stripe: true,
  // border: 'inner',
  'auto-resize': true,
  'keep-source': true,
  'operation-width': '200px', // 操作列宽
  'column-config': { minWidth: '100px', resizable: true },
  'row-config': {
    height: 44,
    keyField: 'id',
    isHover: true
  }
  // 'edit-config': {
  //   trigger: 'dblclick',
  //   mode: 'row',
  //   showStatus: true,
  //   autoClear: true
  // }
}

export function getTableColumnConfig(meta: any) {
  if (!meta) {
    return {}
  }
  return {
    ...Object.keys(meta).reduce((t: any, c: any) => {
      if (configColumnAttrs.includes(c)) {
        t[c] = meta[c]
      }
      return t
    }, {}),
    ...Object.keys(meta.props || {}).reduce((t: any, c: any) => {
      t[c] = meta.props[c]
      return t
    }, {})
  }
}

export function getTableConfig(meta: any, fields?: any) {
  const validateFields = (fields || []).filter((x: any) => x.require && x.display && x.editable)
  const defaultConfig = JSON.parse(JSON.stringify(defaultTableConfig))
  const result = merge(
    {
      'edit-rules': validateFields.reduce((t: any, c: any) => {
        t[c.key] = [{ required: true, message: c.name + '必填' }]
        return t
      }, {})
    },
    Object.keys(meta || {}).reduce((t: any, c: any) => {
      if (configTableAttrs.includes(c)) {
        if (c === 'height' && meta[c] === 'auto') {
          // todo fixed header
          t['max-height'] = `${document.documentElement.clientHeight - 220}px`
        } else if (meta[c] === 'unset') {
          t[c] = undefined
        } else {
          t[c] = meta[c]
        }
      }
      return t
    }, defaultConfig)
  )
  return result
}

// 根据fields生成默认page配置
export function getDefaultGridPage(fields = [], module = 'form') {
  const showFields = fields.filter((col: any) => {
    if (module === 'query') {
      return col.queryable === true || (col.display && col.queryable !== false)
    } else if (module === 'form') {
      return col.editable
    }
    return true
  })
  return {
    config: {
      inline: true,
      'label-width': '100px',
      class: `default${module ? '-' + module : ''}`
    },
    grid: showFields.map((col: any) => ({ field: col.key })),
    module
  }
}

// 根据page.table生成columns配置
export function getPageTableColumns(fields = [], pageFields = []) {
  const newFields = pageFields?.length
    ? pageFields.reduce((t: any, c: any) => {
        const pageCol = typeof c === 'string' ? { field: c } : c
        const fieldKey = pageCol.field || pageCol.key
        const col: any = fields.find((f: any) => f.key === fieldKey)
        if (col) {
          t.push({ ...col, ...pageCol, display: true, field: undefined, key: fieldKey })
        } else {
          t.push({
            ...pageCol,
            display: true,
            field: undefined,
            key: fieldKey
          })
        }
        return t
      }, [])
    : fields
  console.log('tableColumns-------', newFields)
  return newFields
}

// 将数组型数据，转换成map数据
export function convertTableData(list: any, meta: any) {
  if (Array.isArray(list[0])) {
    return list.map((row: any) => {
      if (Array.isArray(row)) {
        return meta.reduce((t: any, c: any, i: number) => {
          t[c.key] = row[i]
          return t
        }, {})
      } else {
        return row
      }
    })
  }
  return list
}
// 初始化fields里的所有source values（异步）
export function initAllValues(fields = []) {
  const filterFields: any = fields.filter(
    (field: any) =>
      !!field.source && (!field.values || field.values.length < 1) && !field._isLoading
  )
  const allPromise = filterFields.map((field: any) => {
    const params = typeof field.source === 'string' ? { source: field.source } : field.source
    return getFormValues({
      ...params,
      size: 10,
      page: 1,
      keyField: undefined,
      nameField: undefined
    })
  })
  filterFields.forEach((col: any) => {
    col._isLoading = true
  })
  Promise.all(allPromise)
    .then((results: any) => {
      results.forEach((result: any, i: number) => {
        const col = filterFields[i]
        col._isLoading = undefined
        filterFields[i].values = result.values
      })
    })
    .finally(() => {
      filterFields.forEach((col: any) => {
        col._isLoading = undefined
      })
    })
}
// 字符串转json
export function parseJSON(jsonStr: any) {
  if (typeof jsonStr === 'string') {
    try {
      return JSON.parse(jsonStr)
    } catch (e) {
      return jsonStr
    }
  }
  return jsonStr
}
// 初始化fields里的所有source values（同步）
export async function initRemoteValues(fields: any, source: any) {
  const reqFields =
    fields?.filter(
      (col: any) =>
        ['enum', 'list', 'string'].includes(col.type) &&
        (col.source || col.pinyin_search) &&
        !col._isLoading
    ) || []
  reqFields.forEach((col: any) => {
    col._isLoading = true
  })
  const reqPromise = reqFields.map((col: any) => {
    if (col.source) {
      const params = typeof col.source === 'string' ? { source: col.source } : col.source
      return getFormValues({
        ...params,
        size: 10,
        page: 1,
        keyField: undefined,
        nameField: undefined
      })
        .then((res: any) => {
          col._isLoading = undefined
          const result = res?.values || []
          if (col.pinyin_search || col.type === 'string') {
            return result.map((x: any) => ({ value: x }))
          } else {
            return result
          }
        })
        .finally(() => {
          col._isLoading = undefined
        })
    } else {
      return getTableList({ source, as_dict: true, page: 1, size: 9999 }).then((res) => {
        const result = res?.data || []
        if (col.pinyin_search || col.type === 'string') {
          return result.map((x: any) => ({ value: x[col.key] }))
        } else {
          return result.map((x: any) => x[col.key])
        }
      })
    }
  })
  await Promise.all(reqPromise)
    .then((res) => {
      res.forEach((r, i) => {
        const col = reqFields[i]
        col.values = r
        // if (col.pinyin_search) {
        //   col._pinyinEngine = new PinyinEngine(col.values || [], ['value'])
        // }
      })
    })
    .catch(() => {})
    .finally(() => {
      reqFields.forEach((col: any) => {
        col._isLoading = undefined
      })
    })
}
// 初始化外键值
export async function initForeignValues(data: any, fields: any, gridFields?: any) {
  if (!data || !fields) {
    return
  }
  const dataList = [data].flat()
  const foreignFields =
    fields?.filter(
      (col: any) =>
        (gridFields ? gridFields.some((x: any) => x.field === col.key) : col.display) &&
        col.key?.includes('.')
    ) || []
  // 过滤配置有foreign和source配置的字段
  const reqFields =
    fields?.filter(
      (col: any) =>
        (gridFields
          ? gridFields.some((x: any) => x.field.split('.')[0] === col.key)
          : col.display) &&
        ((col.foreign && col.foreign.source) || col.source)
    ) || []
  const reqPromise = reqFields.map((col: any) => {
    let ids: any = [
      ...new Set(
        dataList.map((x) => (col.type === 'list' ? parseJSON(x[col.key]) : x[col.key])).flat()
      )
    ].filter((x) => ![null, undefined, ''].includes(x))
    // todo配置有外键的字段，并且需要使用source查询的，查询所有数据，因为异步，此时外键字段还没取到值
    if (col.key?.includes('.') && ids.length < 1) {
      ids = undefined
    } else if (ids.length < 1) {
      return Promise.resolve({ field: col, result: [] })
    }
    if (!col.foreign && col.source) {
      // 如果配置了url使用url的接口
      if (col.source.url) {
        const params = getTemplateData({ ...col.source.params, ...col.source.conditions, ids }, {})
        const url = col.source.url
        return doApi(url, params, col.source.method).then((res) => {
          return { field: col, result: res.data || [] }
        })
      }
      const params = typeof col.source === 'string' ? { source: col.source } : col.source
      return getFormValues({
        ...params,
        keyField: undefined,
        nameField: undefined,
        params: undefined,
        conditions: { ...col.source.params, ...col.source.conditions, ids }
      }).then((res: any) => {
        return { field: col, result: res.values || [] }
      })
    }
    return getForeignValues({ source: col.foreign.source, ids }).then((res: any) => {
      return { field: col, result: res || [] }
    })
  })
  await Promise.all(reqPromise).then((results) => {
    results.forEach((res) => {
      const { result, field } = res
      // field._values = result;
      field._values = mergeResults(field._values, result)
      // 查询了所有数据，临时放在values  todo
      // field.values = mergeResults(field._values, result)
      dataList.forEach((item) => {
        foreignFields.forEach((rField: any) => {
          const fKey = rField.key.split('.')[1]
          if (fKey) {
            item[(gridFields ? '' : '_') + rField.key] = result.find(
              (x: any) => x.id == item[field.key]
            )?.[fKey]
          }
        })
      })
    })
  })
}

// 合并list
export function mergeResults(results = [], list = []) {
  return [
    ...results,
    ...list.filter((x: any) => !results.some((r: any) => (r.id ? r.id === x.id : r.key === x.key)))
  ]
}
// 初始化外键值
export async function initSelectValues(form: any, fields: any, row: any) {
  const foreignFields = fields?.filter((col: any) => col.key.includes('.')) || []
  const reqFields = fields?.filter((col: any) => col.foreign && col.foreign.source) || []
  reqFields.forEach((field: any) => {
    if (field.values) {
      if (!field.values.find((x: any) => x.key == row.id)) {
        field.values.push({ key: row.id, name: row[field.foreign?.field] })
      }
    } else {
      field.values = [{ key: row.id, name: row[field.foreign?.field] }]
    }
  })
  // 过滤配置有foreign
  reqFields.forEach((field: any) => {
    console.log(field)
    // field.values = result.map((v: any) => ({ key: v.id, name: v[field.foreign?.field] }))
    foreignFields.forEach((rField: any) => {
      const fKey = rField.key.split('.')[1]
      if (fKey) {
        form[rField.key] = row?.[fKey]
      }
    })
  })
}
/**
 * 校验unique数据唯一性
 * 传了form判断form在list是否存在，存在返回false，否则返回true
 * 未传form判断list内部是否有重复，重复返回false，否则返回true
 * @param list
 * @param form
 * @param unique
 * @returns
 */
export function isUniqueData(list = [], form: any, unique: any) {
  const uniqueFields = [unique].flat()
  const uniqueSet = list.map((x) => uniqueFields.map((f) => x[f]).join('-*-'))
  // 如果没传form参数，验证list有没有重复
  if (!form) {
    if (new Set(uniqueSet).size != uniqueSet.length) {
      return false
    }
    return true
  }
  const formStr = uniqueFields.map((f) => form?.[f]).join('-*-')
  if (uniqueSet.includes(formStr)) {
    return false
  }
  return true
}
/**
 * 校验unique数据是否同一类型
 * @param list
 * @param unique
 * @returns
 */
export function isSameData(list = [], unique: any) {
  const uniqueFields = [unique].flat()
  const uniqueSet = list.map((x) => uniqueFields.map((f) => x[f]).join('-*-'))
  return new Set(uniqueSet).size <= 1
}
// 递归获取grid配置的默认值value
export function getGridDefaultValue(page: any, conditions?: any, row?: any) {
  const form: any = {
    ...conditions
  }
  const userInfo = {}
  const recursionGrid = (grid: any) => {
    if (grid?.field && row && row[grid.field] !== null && row[grid.field] !== undefined) {
      form[grid.field] = row[grid.field]
    } else if (grid?.field && grid.value !== null && grid.value !== undefined) {
      if (/\$\{.+\}/.test(grid.value)) {
        form[grid.field] = template(grid.value)({ userInfo, ...row })
      } else {
        form[grid.field] = grid.value
      }
    }
    if (grid?.grid && Array.isArray(grid.grid)) {
      grid.grid.forEach((g: any) => {
        recursionGrid(g)
      })
    }
  }
  recursionGrid(page)
  return form
}
// 递归获取grid配置的字段列表
export function getGridFields(page: any, form?: any) {
  const results: any = []
  const recursionGrid = (grid: any) => {
    if (grid?.field) {
      const item: any = { ...grid, field: grid?.field }
      if (grid.value !== null && grid.value !== undefined) {
        item.value = grid.value
      }
      if (form?.[grid.field] !== null && form?.[grid.field] !== undefined) {
        item.value = form?.[grid.field]
      }
      results.push(item)
    }
    if (grid?.grid && Array.isArray(grid.grid)) {
      grid.grid.forEach((g: any) => {
        recursionGrid(g)
      })
    }
  }
  recursionGrid(page)
  return results
}
// 合并fields
export function mergeFields(pageFields = [], metaFields = []) {
  return pageFields && pageFields.length > 0
    ? pageFields
        .map((field: any) => {
          const findField: any = metaFields.find((col: any) =>
            typeof field === 'object' ? (field.key || field.field) === col.key : field === col.key
          )
          if (typeof field === 'object') {
            return { ...findField, ...field, display: true }
          } else if (findField) {
            return { ...findField }
          } else {
            return undefined
          }
        })
        .filter((x) => !!x)
    : metaFields
}
// 合并grid和fields
export function getMergeGridFields(pageGrid: any, metaFields = []) {
  const pageFields = getGridFields(pageGrid)
  return mergeFields(pageFields, metaFields)
}
// 通用按钮配置
export let StandardOperations = []
export async function getStandardOperations() {
  if (StandardOperations.length < 1) {
    const yamlReq = await fetch('./project/table/standard_operations.yaml')
    StandardOperations = await jsyaml.load(await yamlReq.text())
  }
  return StandardOperations
}
// 合并按钮
export async function mergeOperations(operations: any) {
  const standardOperations = await getStandardOperations()
  if (operations && operations.length > 0) {
    return Object.values(
      [...standardOperations, ...operations].reduce((t, c) => {
        t[c.key] = c
        return t
      }, {})
    )
  }
  return standardOperations
}
// 获取缓存的跳转路由对象
export function getRouteParams() {
  const { path } = useRoute()
  const pageroute = JSON.parse(sessionStorage.getItem('pageroute') || '{}')
  console.log(pageroute, path)
  if (pageroute?.path === path) {
    // 使用完就删除
    sessionStorage.removeItem('pageroute')
    return pageroute.params
  }
  return null
}

// 校验是否显示
export function checkVisible(op: any, row: any) {
  return (
    !op.visible ||
    (row &&
      [op.visible]
        .flat()
        .some((vis) =>
          typeof vis === 'string'
            ? template(vis)({ ...row, $dayjs: dayjs }) == 'true'
            : Object.keys(vis).every((key) => [vis[key]].flat().includes(row[key]))
        ))
  )
}

// 校验是否禁用
export function checkDisabled(op: any, row: any) {
  // 配置了enabled
  if (op.hasOwnProperty('enabled')) {
    return !(typeof op.enabled === 'boolean'
      ? op.enabled
      : row &&
        [op.enabled]
          .flat()
          .some((vis) =>
            typeof vis === 'string'
              ? template(vis)({ ...row, $dayjs: dayjs }) == 'true'
              : Object.keys(vis).every((key) => [vis[key]].flat().includes(row[key]))
          ))
  } else if (op.hasOwnProperty('disabled')) {
    return (
      !op.disabled ||
      (row &&
        [op.disabled]
          .flat()
          .some((vis) =>
            typeof vis === 'string'
              ? template(vis)({ ...row, $dayjs: dayjs }) == 'true'
              : Object.keys(vis).every((key) => [vis[key]].flat().includes(row[key]))
          ))
    )
  } else {
    return false
  }
}

// 根据permissions返回权限配置
export function getPermissions(permissions: any) {
  const ps = [permissions]
    .flat()
    .filter((x) => !!x)
    .map((x) => x)
  if (ps && ps.length > 0) {
    return ps
  } else {
    return undefined
  }
}

// 根据permissions判断是否有权限
export function hasPermissions(permissions: any) {
  const ps = getPermissions(permissions)
  if (!ps) {
    return true
  }
  const permissionStore = usePermissionStoreWithOut()
  if (permissionStore.getPermissions) {
    return ps.length < 1 || permissionStore.getPermissions.some((x: any) => ps.includes(x))
  }
  return false
}

// 根据columns列字段，生成默认page配置
export function getFormByColumns(columns: any = []) {
  if (!columns?.length) {
    return {}
  }
  return {
    config: {
      'label-position': 'left',
      'label-width': '120px'
    },
    module: 'form',
    style: '',
    grid: columns
      .filter((col: any) => col.editable)
      .map((col: any) => ({
        field: col.key
      }))
  }
}

// 返回处理后，显示的数据name
export function getShowData(data: any, columns: any = []) {
  const list = JSON.parse(JSON.stringify([data].flat()))
  list.forEach((item: any) => {
    columns.forEach((col: any) => {
      const values = col.values || col._values
      if (col.type === 'enum' && values && item.hasOwnProperty(col.key) && item[col.key]) {
        const val = item[col.key]
        const key =
          (typeof col.source === 'string' || col.foreign ? 'id' : col.source?.keyField) || 'key'
        const findVal = values.find((x: any) => (typeof x === 'object' ? x[key] == val : x == val))
        item[col.key] =
          typeof findVal === 'object'
            ? findVal[col?.source?.nameField || col.foreign?.field || 'name']
            : findVal
      }
    })
  })
  if (Array.isArray(data)) {
    return list
  } else {
    return list[0]
  }
}

// 将标准yaml配置，转化成注册form配置
export function convertRegistFormConfig(fields: any = []) {
  const { required } = useValidator()
  const { t } = useI18n()
  return fields.map((item: any) => {
    const temp: any = {
      field: item.key,
      label: item.name,
      value: item.value || item.default || '',
      colProps: {
        span: 24
      },
      componentProps: {
        ...item.props,
        placeholder: item.placeholder || ''
      },
      formItemProps: {
        ...(item.require || item.required
          ? {
              rules: [required(t('common.required'))]
            }
          : {})
      }
    }
    switch (item.type) {
      case 'enum':
        temp.component = 'Select'
        if (!item.placeholder) {
          temp.componentProps.placeholder = '请选择'
        }
        temp.componentProps.options = (item.values || []).map((x) =>
          typeof x === 'string' ? { label: x, value: x } : { label: x.name, value: x.key }
        )
        break
      case 'string':
      default:
        temp.component = 'Input'
        if (!item.placeholder) {
          temp.componentProps.placeholder = '请输入'
        }
        break
    }
    return temp
  })
}

// 转换字符串到数组缓冲区，XLSX需要
function s2ab(s: string) {
  const buf = new ArrayBuffer(s.length)
  const view = new Uint8Array(buf)
  for (let i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xff
  return buf
}

export function enumForeignValue(row: any, col: any, fields: any) {
  const keys = col.key.split('.')
  const mainKey = keys[0]
  const showKey = keys[1]
  const mainCol = fields.find((x) => x.key === mainKey)
  if (mainCol && showKey) {
    const mainSource = mainCol.source
    const values = mainCol.values || mainCol._values || []
    const findValue =
      values.find((v: any) => row[mainKey] === v[mainSource.keyField || 'id'])?.[showKey] || ''
    if (col.type === 'enum') {
      const targetValues = col.values || col._values || []
      return (
        targetValues.find((v: any) => findValue === v[col?.source?.keyField || 'key'])?.[
          col?.source?.nameField || 'name'
        ] || findValue
      )
    } else {
      return findValue
    }
  }
  return ''
}

export function downloadLists(columns: any[], list: any[], xlsxName?: string) {
  const exlArr: {}[] = []
  list.forEach((item) => {
    const obj: any = {}
    columns
      .filter((col) => col.display === true)
      .forEach((col) => {
        if (col.key.includes('.')) {
          obj[col.name] = enumForeignValue(item, col, columns)
        } else if (col.type === 'enum') {
          const values = col._values || col.values || []
          const val = values.find(
            (v: any) =>
              (typeof v === 'object' ? `${v[col?.source?.keyField || 'key']}` : v) ===
              `${item[col.key]}`
          )
          obj[col.name] =
            (val && typeof val === 'object' ? val[col?.source?.nameField || 'name'] : val) ||
            item[col.key]
        } else {
          obj[col.name] = item[col.key]
        }
      })
    exlArr.push(obj)
  })
  // 假设你有一个表格数据的ref
  const tableData = exlArr

  // 创建工作簿
  const workbook = XLSX.utils.book_new()

  // 将表格数据转换为工作表
  const worksheet = XLSX.utils.json_to_sheet(tableData)

  // 将工作表添加到工作簿
  XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1')

  // 生成Excel的配置
  const wbout = XLSX.write(workbook, { bookType: 'xlsx', type: 'binary' })

  // 创建二进制对象并创建url
  const blob = new Blob([s2ab(wbout)], { type: 'application/octet-stream' })
  const url = URL.createObjectURL(blob)

  // 创建a标签模拟点击进行下载
  const a = document.createElement('a')
  if (typeof a.download === 'undefined') {
    window.location.href = url
  } else {
    a.href = url
    const date = xlsxName || new Date().getTime()
    a.download = date + '.xlsx'
    document.body.appendChild(a)
    a.click()
    document.body.removeChild(a)
  }

  // 清除对象URL
  setTimeout(function () {
    URL.revokeObjectURL(url)
  }, 0)
}

export function inputQuerySearch(qs, cb, col, row) {
  let results = []
  if (col._pinyinEngine) {
    const values = col.values.map((x) => (typeof x === 'string' ? { name: x } : x))
    results = qs ? col._pinyinEngine.query(qs) : values
    cb(results)
  } else if (col.source && !col.values?.length) {
    const sourceObj = {
      ...(typeof col.source === 'string' ? { source: col.source } : col.source)
    }
    const conditions = {}
    Object.keys(sourceObj.conditions || {}).forEach((key) => {
      try {
        const value = template(sourceObj.conditions[key])(row || {})
        if (!value.includes('${')) {
          conditions[key] = value
        }
      } catch (e) {
        // conditions[key] = sourceObj.conditions[key];
      }
    })
    if (sourceObj.url) {
      doApi(sourceObj.url, { ...sourceObj, conditions }, sourceObj.method)
        .then((res) => {
          results = (res.data || []).map((x) => ({
            name: (sourceObj.nameField && x[sourceObj.nameField]) || x.name
          }))
          col.values = results
          cb(results)
        })
        .finally(() => {})
    } else {
      getFormValues({
        ...sourceObj,
        conditions,
        keyField: undefined,
        nameField: undefined
      })
        .then((res: any) => {
          results = res.values || []
          col.values = results
          cb(results)
        })
        .finally(() => {})
    }
  } else if (col.values?.length) {
    const values = col.values.map((x) => (typeof x === 'string' ? { name: x } : x))
    col._pinyinEngine = new PinyinEngine(values || [], ['name'])
    results = qs ? col._pinyinEngine.query(qs) : values
    cb(results)
  }
}

// enum显示
export function showEnumValues(value: any, col: any) {
  // const field = props.meta.find((m) => m.key === col.key);
  const values = col?._values || col?.values || []
  if (col?.foreign) {
    const val = values.find((v: any) => `${v[col?.foreign?.key || 'id']}` === `${value}`)
    return val?.[col?.foreign?.field]
  } else {
    const val = values.find(
      (v: any) =>
        (typeof v === 'object' ? `${v[col?.source?.keyField || 'key']}` : v) === `${value}`
    )
    return (val && typeof val === 'object' ? val[col?.source?.nameField || 'name'] : val) || value
  }
}

// list显示
export function showListValues(value: any, col: any) {
  const vals = typeof value === 'string' && /\[.+\]/.test(value) ? JSON.parse(value) : value
  if (Array.isArray(vals)) {
    // const field = props.meta.find((m) => m.key === col.key);
    // const values = field?._values || field?.values || [];
    return vals
      .map((vl) => {
        // const val = values.find((v) => (typeof v === "object" ? `${v.key}` : v) === `${vl}`);
        // return (val && typeof val === "object" ? val.name : val) || vl;
        return showEnumValues(vl, col)
      })
      .join(',')
  } else {
    return showEnumValues(value, col)
  }
}

// 根据规则校验form（rules规则配置和el-form一致）
export async function validateForm(form: any, rules: any) {
  return new Promise((resolve) => {
    if (!rules) {
      resolve(null)
    }
    const validator = new Schema(rules)
    validator.validate(form, (errors: any) => {
      resolve(errors)
    })
  })
}

// 执行一条ajax
export async function doAjax(row: any, op: any, scope: any) {
  const url = op.ajax.url
  console.log(scope)
  // ajax的参数
  const params = op.ajax.params
    ? Object.keys(op.ajax.params || {}).reduce((t: any, c: any) => {
        try {
          // 如果包含有relationList
          if (/\$\{relationList((\[\d+\])|(\.+\S+)*)\}/.test(op.ajax.params[c])) {
            t[c] = get(scope, op.ajax.params[c].replace('${', '').replace('}', ''))
          } else {
            const compiled = template(op.ajax.params[c])
            t[c] = compiled({ ...scope, ...row })
          }
          return t
        } catch (e) {
          return t
        }
      }, {})
    : row
  if (op.ajax.validate) {
    const valid: any = await validateForm(params, op.ajax.validate)
    if (valid) {
      ElMessage.warning(valid[0]?.message)
      return Promise.reject(valid[0]?.message)
    }
  }
  const method = op.ajax.method || 'get'
  const results = op.ajax.results // 执行成功后，修改row数据
  const message = op.ajax.message || '' // 执行成功后，提示信息
  const resultData = await doApi(url, params, method)
  if (row && results) {
    Object.keys(results).forEach((field) => {
      const compiled = template(results[field])
      if (
        op?.ajax?.resultForm &&
        scope &&
        scope[op.ajax.resultForm] &&
        typeof scope[op.ajax.resultForm] === 'object'
      ) {
        scope[op.ajax.resultForm][field] = compiled(resultData)
      } else {
        row[field] = compiled(row)
      }
    })
  }
  if (message) {
    if (row && message) {
      try {
        const compiled = template(message)
        ElMessage.success(compiled({ ...row, ...resultData }))
      } catch (e) {
        ElMessage.success(message)
      }
    }
  }
}

export function getPreviewType(url: any) {
  const suffix = url.split('.').reverse()[0]
  if (['jpg', 'jpeg', 'png', 'gif'].includes(suffix)) {
    return 'image'
  } else if (['mp4'].includes(suffix)) {
    return 'mp4'
  } else if (['yaml', 'yml'].includes(suffix)) {
    return 'yaml'
  } else if (['json'].includes(suffix)) {
    return 'json'
  }
}

// 文件预览
export function doPreview(previewContent: any, preview: any) {
  const previewType = preview === true ? getPreviewType(previewContent) : preview
  if (['rtsp', 'video', 'mp4'].includes(previewType) && previewContent) {
    StreamPreview({
      url: previewContent
    })
  } else if (['yaml', 'json'].includes(previewType) && previewContent) {
    ContentEditor({
      type: previewType,
      content: typeof previewContent === 'object' ? JSON.stringify(previewContent) : previewContent
    })
  } else if (['img', 'image', 'thumbnail'].includes(previewType) && previewContent) {
    createImageViewer({
      urlList: [previewContent],
      hideOnClickModal: true
    })
  } else if (previewContent) {
    FilePreview({
      url: previewContent,
      type: previewType
    })
  }
}
